# include <bits/stdc++.h>
# define mid ((l + r) >> 1)
# define MAXN 100002
using namespace std;
inline int r_int() {
	int k = 0, f = 1;
	char c = getchar();
	for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for(; isdigit(c); c = getchar()) k = k * 10 + c - '0';
	return k * f;
}
int n, q;
struct node{
	node *ls, *rs;
	int mx;
	inline node() {
		ls = rs = NULL;
	}
}*root[MAXN];
int cnt = 1;
node* build(int l, int r) {
	node *p = new node();
	if(l == r) {
		p->mx = r_int();
	} else {
		p->ls = build(l, mid);
		p->rs = build(mid + 1, r);
		p->mx = max(p->ls->mx, p->rs->mx);
	}
	return p;
}
node* change(node *pre, int k, int x, int l, int r) {
	node *p = new node();
	if(l == r) {
		p->mx = x;
		return p;
	} else if(k <= mid) {
		p->ls = change(pre->ls, k, x, l, mid);
		p->rs = pre->rs;
	} else {
		p->ls = pre->ls;
		p->rs = change(pre->rs, k, x, mid + 1, r);
	}
	p->mx = max(p->ls->mx, p->rs->mx);
	return p;
}
int query(node *p, int l, int r, int s, int t) {
	if(l == s && r == t) return p->mx;
	else if(t <= mid) return query(p->ls, l, mid, s, t);
	else if(s > mid) return query(p->rs, mid + 1, r, s, t);
	else {
		return max(query(p->ls, l, mid, s, mid), query(p->rs, mid + 1, r, mid + 1, t));
	}
}
int main() {
	freopen("longterm_segtree.in", "r", stdin);
	freopen("longterm_segtree.out", "w", stdout);
	n = r_int();
	q = r_int();
	root[1] = build(1, n);
	while(q--) {
		if(r_int()) {
			int k = r_int();
			int p = r_int();
			int v = r_int();
			root[++cnt] = change(root[k], p, v, 1, n);
		} else {
			int k = r_int();
			int s = r_int();
			int t = r_int();
			printf("%d\n", query(root[k], 1, n, s, t));
		}
	}
	return 0;
}
